﻿using System;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Collections.ObjectModel;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace Real.Silverlight.Controls
{
    public static class Extensions
    {

        #region extensions for client-side sorting
        /// <summary>
        /// Convert an IEnumberable to an ObservableCollection
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="list"></param>
        /// <returns></returns>
        public static ObservableCollection<T> ToObservableCollection<T>(this IEnumerable<T> list)
        {
            var col = new ObservableCollection<T>();
            foreach (var item in list)
            {
                col.Add(item);
            }
            return col;
        }


        private static Func<TSource, TKey> CreateKeySelector<TSource, TKey>(MemberInfo member)
        {
            Func<TSource, object> getMemberValue = c => (member is FieldInfo)
                    ? ((FieldInfo)member).GetValue(c)
                    : (member is PropertyInfo)
                        ? ((PropertyInfo)member).GetValue(c, null)
                        : null;

            if (getMemberValue == null)
                throw new NotSupportedException("Only property or field members are supported.");

            Func<TSource, TKey> ret = c => (TKey)getMemberValue(c);

            return ret;
        }

        public static IOrderedEnumerable<T> OrderBy<T>(this IEnumerable<T> source, string memberName)
        {
            var mem = typeof(T).GetMember(memberName).Single();

            var memType = (mem is FieldInfo)
               ? ((FieldInfo)mem).FieldType
               : ((PropertyInfo)mem).PropertyType;

            var keySelector = typeof(Extensions)
                .GetMethod("CreateKeySelector", BindingFlags.Static | BindingFlags.NonPublic)
                .MakeGenericMethod(typeof(T), memType).Invoke(null, new object[] { mem });

            var orderByMeth = typeof(Enumerable).GetMethods()
                .Where(c => c.Name == "OrderBy")
                .Where(c => c.GetParameters().Count() == 2)
                .Single()
                .MakeGenericMethod(typeof(T), memType);

            return orderByMeth.Invoke(null, new object[] { source, keySelector }) as IOrderedEnumerable<T>;
        }

        public static IOrderedEnumerable<T> OrderByDescending<T>(this IEnumerable<T> source,
            string memberName)
        {
            var mem = typeof(T).GetMember(memberName).Single();

            var memType = (mem is FieldInfo)
               ? ((FieldInfo)mem).FieldType
               : ((PropertyInfo)mem).PropertyType;

            var keySelector = typeof(Extensions)
                .GetMethod("CreateKeySelector", BindingFlags.Static | BindingFlags.NonPublic)
                .MakeGenericMethod(typeof(T), memType).Invoke(null, new object[] { mem });

            var orderByMeth = typeof(Enumerable).GetMethods()
                .Where(c => c.Name == "OrderByDescending")
                .Where(c => c.GetParameters().Count() == 2)
                .Single()
                .MakeGenericMethod(typeof(T), memType);

            return orderByMeth.Invoke(null, new object[] { source, keySelector }) as IOrderedEnumerable<T>;
        }

        #endregion
    }
}
